constraints and concepts
https://cppreference.com/w/cpp/language/constraints.html
限制可以更好的帮助模板类、模板函数、模板化函数选择更合适的模板特化、重载。
Concept
命名的一组需求(requiremetns)称为概念(concepts)。概念是一个编译期谓词,用于可以精细而简洁地限定模板的适用范围。其作为限制(Constraint)作用于模板参数类型上时,最终会成为所作用的模板的接口的一部分。
template <template_parameter_list>
concept concept_name attr = constraint_expression;
concept 无法递归定义,其本身无法被限制,无法实例化
concept 的使用:
- 作为模板的类型参数限制
template<Concept T> void f(T) {}
,其中Concept
是一个 concept - 作为
auto
的自动推导类型的限制 - 作用于 constraint-expression 中
- 作为 requires expression 中 compound requirements 中对表达式求值类型的限制
- 出现在 requires clauses 中
- 形式 1
template<typename T> requires Concept<T> void f(T) {}
- 形式 2
template<typename T> void f(T) requires Concept<T> {}
- 形式 1
- 作为 id-expression 出现时,求值结果不为该标识符所代表的实体,而是一个布尔值
其中 concept 作为 type-constraint 时接受的第一个参数隐式地使用根据语境推导的类型,如果存在。
概念是一种语义范畴而不是语法约束
- 语义化的概念能容易传达设计意图,纯粹的语法检查只是底层工具
Require Clauses
require clauses 是除了 concept 之外第二种引入限制的方式
- requires clauses 1
template<typename T> requires constraint-expression void f(T) {}
- requires clauses 2
template<typename T> void f(T) requires constraint-expression {}
其中的 constraint-expression 必须为 primary expression 及其 && || 的结果
Constraint
constraint-expression 是求值为 bool 的常量表达式,包括但不限于
- concept
- require expression
- && || 组合以上
constraint-expression 是 concept 和 require-clauses 的重要组成部分。
引入限制的方式包括:concept,require clauses。
constraint 可以用于修饰模板声明,一个声明被修饰的所有限制按 logic AND 以如下顺序依次确定(对应四种 constraint 被引入的方式),经过约束规范化形成原子约束等,然后被检查。
- 模板参数
- requires clauses 1
template<typename T> requires constraint-expression void f(T) {}
- requires clauses 2
template<typename T> void f(T) requires constraint-expression {}
实例化之前的称为约束表达式;经过约束规范化之后的(即实例化之后的) constraint 分为四种
- conjunctions,短路
- disjunctions,短路
- atomic constaints,包含表达式 E 和一个从 E 中模板参数到被约束的模板化实体的模板形参的参数映射。原子约束被检查的过程:替换参数映射和模板实参入 E 并进行类型、表达式有效性验证,确保替换后的 E 是 bool prvalue(可能存在编译期自动执行的左右值转换) 常量表达式(要求严格类型 bool,不允许隐式类型转换后的)
- fold expanded constaints
重声明需要保证两次声明中限制出现的位置和顺序相同(syntatically identical instead of logically identical),否则是非法的,no diagnostics required。
限制的包含关系:
- P "包含" Q 定义为 P 析取范式的每一个析取子句都包含 Q 合取范式的每一个合取子句。
- 析取子句包含合取范式当且仅当,析取子句存在一条包含合取子句某一原子约束的原子约束。(推论:原子约束的 A 包含 B 当且仅当 A = B)
注意这里的"包含"仅是语法上的结构性包含,并不是语义上的包含,而且该定义也仅仅是充分而不必要的。
约束的包含关系定义了约束的应用偏序
- To be continued
违反限制会在模板实例化之前造成”违反限制“的编译错误,而不是在模板被错误使用时才造成对应错误使用方式的编译错误。